#include "common.h"
#include "../mapobjects/objectstorage.h"

#include "index.h"

#include <QtCore/QFile>
#include <QtCore/QDataStream>


Index::Index()
{
    //ctor
}

Index::~Index()
{
    //dtor
}

bool isLetter ( char c )
{
	return c >= 'a' && c <='z' || c >='A' && c <= 'Z';
}

void getWords ( string str, vector<string> & result )
{
	result.clear();
    size_t i = 0;
    while ( i < str.size ())
    {
        size_t start = i;
        while ( i < str.size() && isLetter ( str[i] ))
            ++i;
        string addStr = str.substr ( start, i - start );
        if ( 0 == addStr.size())
        {
            ++i;
            continue;
        }
        result.push_back ( addStr );
        ++i;
    }
}


void Index::makeDict ( ObjectStorage * objStorage )
{
    vector<MapObject *> mapObjects;
    objStorage -> getMapObjects ( mapObjects );

    for ( size_t i = 0; i < mapObjects.size(); ++i )
    {
        addMapObject ( mapObjects[i] );
    }


    QHashIterator<QString, Entry *> i (dict);
    while (i.hasNext())
    {
        i.next();
        Entry * e = i.value();
        qSort ( e -> documents );
    }
}

void Index::addMapObject ( MapObject * mapObject )
{
    vector<EPropType> types;
    mapObject -> getPropertyTypeList ( types );
    for ( size_t i = 0; i < types.size(); ++i )
    {
        if ( GetVariableType ( types[i] ) == stringType )
        {
            string str;
            mapObject -> getProperty ( types[i], str );
            addString ( mapObject, str );
        }
    }
}

void Index::addString ( MapObject * mapObject, string & str )
{
	vector<string> words;
	getWords ( str, words );
	for ( size_t i = 0; i < words.size(); ++i )
	{
		addWord ( mapObject, words[i] );
	}
}

void Index::addWord ( MapObject * mapObject, string & str )
{
    Entry *e = 0;
    if ( dict.count() )
        e = dict[ str.data() ];

    if ( e ) {
        if ( e->documents.last().mapObject != mapObject )
            e->documents.append( Document( mapObject, 1 ));
        else
            e->documents.last().frequency++;
    } else {
        dict.insert( str.data(), new Entry( mapObject ) );
    }
}

void Index::getObjectListByString ( string & str, vector<MapObject *> & vect )
{
	vector<string> words;
	getWords ( str, words );
	vector < vector < MapObject * > > lists;
	lists.resize ( words.size ());
	for ( size_t i = 0; i < words.size(); ++i )
	{
		getObjectListBySingleString ( words[i], lists[i] );
	}

	if ( words.size() == 1 )
	{
		vect = lists[0];
		return;
	}

	vector<int> listFound ( lists[0].size(), 0 );

	for ( size_t i = 0; i < lists[0].size(); ++i )
	{
		bool found = false;
		for ( size_t j = 1; j < lists.size(); ++j )
		{
			for ( size_t k = 0; k < lists[j].size(); ++k )
			{
				if ( lists[0][i] == lists[j][k] )
				{
					found = true;
					break;
				}
			}
			if ( found )
				break;
		}
		if ( found )
			listFound[i] = 1;
	}
	
	vect.clear ();
	for ( size_t i = 0; i < lists[0].size(); ++i )
	{
		if ( 1 == listFound[i] )
			vect.push_back ( lists[0][i] );
	}
}

void Index::getObjectListBySingleString ( string & str, vector<MapObject *> & vect )
{
    Entry * e = dict [ str.data() ];
    if ( 0 == e )
    {
        vect.resize ( 0 );
        return;
    }

    vect.resize ( e -> documents.size() );
    for ( size_t i = 0; i < vect.size(); ++i )
    {
        vect[i] = e -> documents[(int) i].mapObject;
    }
}

void Index::saveDict ( QString fileName )
{
	QFile f ( fileName );
	f.open ( QIODevice::WriteOnly );
	QDataStream stream ( &f );
	QHash<QString, Entry*>::iterator it;
	for ( it = dict.begin(); it != dict.end(); ++it )
	{
		stream << it.key ();
		Entry * e = it.value ();
		stream << e -> documents.size();
		for ( int i = 0; i < e -> documents.size(); ++i )
		{
			MapObject * mapObject = e -> documents[i].mapObject;
			int id = mapObject -> getID ();
			stream << id;
		}
	}
	f.close ();
}

void Index::loadDict ( QString fileName, ObjectStorage * storage )
{
	QFile f ( fileName );
	f.open ( QIODevice::ReadOnly );
	QDataStream stream ( &f );
	dict.clear ();

	while ( ! f.atEnd ())
	{
		QString str;
		stream >> str;
		int size;
		stream >> size;
		Entry * e = NULL;
		for ( int i = 0; i < size; ++i )
		{
			int id;
			stream >> id;
			MapObject * mapObject = storage -> getObjectByID ( id );
			if ( NULL == e )
				e = new Entry ( mapObject );
			else
				e -> documents.append ( Document ( mapObject, 1 ));
		}
	}
}
